package com.sxyc.tintin.sdk;

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.amitek.service.bean.RemoteException;
import com.amitek.service.bean.ServiceException;
import com.amitek.service.bean.protocol.AlarmType;
import com.amitek.service.bean.protocol.BindType;
import com.amitek.service.bean.protocol.ObdInfo;
import com.amitek.service.bean.protocol.PosInfo;
import com.amitek.service.bean.protocol.StatInfo;
import com.amitek.service.bean.protocol.TrackInfo;
import com.amitek.service.bean.request.BindStatus;
import com.amitek.service.bean.request.UploadType;
import com.amitek.service.bean.request.BindStatus.UserInfo;
import com.amitek.service.bean.request.DestInfo;
import com.amitek.service.bean.request.MediaType;
import com.amitek.service.bean.request.ReqType;
import com.amitek.service.bean.response.DeviceInfo;
import com.amitek.service.bean.response.PosResult;
import com.amitek.service.bean.response.TrackDesc;
import com.amitek.service.bean.response.TrackList;
import com.amitek.service.bean.response.TrackStatus;
import com.amitek.service.callback.AbstractCallback.NotifyAlarmCallback;
import com.amitek.service.callback.AbstractCallback.NotifyDeviceCallback;
import com.amitek.service.callback.AbstractCallback.NotifyTrackStartCallback;
import com.amitek.service.callback.AbstractCallback.NotifyTrackStopCallback;
import com.amitek.service.callback.AbstractCallback.NotifyUploadCallback;
import com.amitek.service.callback.AbstractCallback.ReportObdCallback;
import com.amitek.service.callback.AbstractCallback.ReportPosCallback;
import com.amitek.service.callback.AbstractCallback.ReportTrackCallback;
import com.amitek.service.callback.AbstractCallback.RequestBindCallback;
import com.amitek.service.callback.AbstractCallback.RequestChargeCallback;
import com.amitek.service.callback.AbstractCallback.RequestConfigCallback;
import com.amitek.service.callback.AbstractCallback.ResponseResultCallback;
import com.amitek.service.rabbitmq.RabbitJsonRpcClient;
import com.amitek.service.rabbitmq.RabbitJsonRpcServer;
import com.amitek.service.rabbitmq.RabbitService;
import com.amitek.service.rabbitmq.RabbitWrapper;
import com.amitek.service.service.ServiceFactory;
import com.amitek.service.service.ServiceInstance;
import com.jfinal.kit.HttpKit;
import com.jfinal.kit.PropKit;
import com.sxyc.tintin.model.Device;
import com.sxyc.tintin.model.DeviceBinding;
import com.sxyc.tintin.model.Drivingrange;
import com.sxyc.tintin.model.MediaUpload;
import com.sxyc.tintin.model.WxUser;
import com.sxyc.utils.QMapUtils;

public class SDKUtils {

	// 使用jFinal 日志
	private static com.jfinal.log.Log log = com.jfinal.log.Log.getLog(SDKUtils.class);

	private static ServiceInstance serviceInstance = null;

	private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	
	/**
	 * 启动Service
	 */
	public static void start() {
		log.info("启动 RabbitService 服务 ...");

		// 设置系统参数
		RabbitService.setRequestTimeout(10000);
		RabbitWrapper.setReconnect(true, 5000);
		RabbitWrapper.setTimeout(3000, 3000, 3000, 0);
		RabbitJsonRpcClient.setDebugEnabled(false);
		RabbitJsonRpcServer.setDebugEnabled(false);

		// 初始化参数
		String serverUrl = PropKit.get("serverUrl", "amqp://mq.ami-tek.com.cn:5672");
		String serviceId = PropKit.get("serviceId", "cbd");
		String servicePassword = PropKit.get("servicePassword", "123456");
		String clientId = PropKit.get("clientId", null);

		log.info("配置参数：");
		log.info("serverUrl = " + serverUrl);
		log.info("serviceId = " + serviceId);
		log.info("servicePassword = " + servicePassword);
		log.info("clientId = " + clientId);

		// 如果服务未运行则启动
		while (!RabbitService.isStarted()) {
			try {
				RabbitService.start(serverUrl, serviceId, servicePassword, clientId);
				log.info("连接 RabbitMQ 服务器成功!");
			} catch (Exception e) {
				try {
					Thread.sleep(1000);
				} catch (InterruptedException iex) {

				}
				log.info("连接 RabbitMQ 服务器失败!正在重新连接 ...");
			}
		}
	}

	/**
	 * 停止Service
	 */
	public static void stop() {
		log.info("停止 RabbitService 服务 ...");

		if (RabbitService.isStarted()) {
			RabbitService.stop();
			// RabbitService.stop(1000);//等待底层完成现有消息发送和接收的时间
		}
	}

	/**
	 * 初始化Service
	 */
	public static void init() {
		log.info("初始化服务 ...");

		log.info("开始注册回调函数 ...");
		registerCallback();
	}

	public static void initOther() {
		log.info("初始化其他 ...");
		if (!RabbitService.isStarted()) {
			log.info("服务未启动，不能注册回调函数 ...");
		} else {
			serviceInstance = ServiceFactory.getServiceInstance();
		}
		// updateAllTinTinWxUser();
		// updateTinTinWxUser();
		// updateBinding();
	}

	private static String getToken() {
		String token = "";
		try {
			String tokenUrl = "http://wechat.ami-tek.com.cn/e00c373bd430/application/wx/common.php?m=getAccessToken2";
			String tokenResult = HttpKit.get(tokenUrl);
			if (tokenResult != null && !"".equals(tokenResult)) {
				JSONObject tokenOject = JSONObject.parseObject(tokenResult);
				token = tokenOject.getString("access_token");
			}
		} catch (Exception e) {
			log.error("getToken Exception ：" + e.getMessage());
		}
		return token;
	}

	private static void updateAllTinTinWxUser() {
		// 查询微信所有用户信息
		try {
			String token = getToken();
			String getUserUrl = "https://api.weixin.qq.com/cgi-bin/user/get?access_token=" + token;
			String getUserResult = HttpKit.get(getUserUrl);
			if (getUserResult != null && !"".equals(getUserResult)) {
				JSONObject userOject = JSONObject.parseObject(getUserResult);
				int count = userOject.getIntValue("count");
				log.info("共获取到微信用户数："+count);
				JSONArray openIdList = userOject.getJSONObject("data").getJSONArray("openid");
				if (openIdList != null && openIdList.size() > 0) {
					for (Object object : openIdList) {
						String openId = object.toString();
						try {
							WxUser user = WxUser.dao.getWxUser(openId);
							if (user == null) {
								user = new WxUser();
								user.set("OpenId", openId);
								user.set("AppID", "wxc0feefca7c7dc010");
								user.set("CreatedBy", "System");
								user.set("CreatedDate", new Date());
								user.set("UpdatedBy", "System");
								user.set("UpdatedDate", new Date());
								user.set("Status", "1");
								boolean isSuccess = user.save();
								if (isSuccess) {
									log.info("保存OpenId为 [ " + openId + " ] 的用户成功！");
								} else {
									log.info("保存OpenId为 [ " + openId + " ] 的用户失败！");
								}
							}
						} catch (Exception ex) {
							log.info("保存OpenId为 [ " + openId + " ] 的用户异常！原因："+ex.getMessage());
						}
					}
				}
			}
		} catch (Exception e) {
			log.error("getWxUser Exception：" + e.getMessage());
		}
	}

	private static void updateTinTinWxUser(){
		try {
			String token = getToken();
			List<WxUser> userList = WxUser.dao.getAllWxUser();
			if (userList != null && userList.size() > 0) {
				log.info("userList.size = " + userList.size());
				for (WxUser wxUser : userList) {

					String openId = wxUser.getStr("OpenId");
					log.info("openId = " + openId);
					
					// 获取微信用户信息
					try {
						String getUserInfoUrl = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + token
								+ "&openid=" + openId + "&lang=zh_CN";
						String getUserInfoResult = HttpKit.get(getUserInfoUrl);
						log.info("getUserInfoResult = " + getUserInfoResult);
						if (getUserInfoResult != null && !"".equals(getUserInfoResult)) {
							JSONObject userOject = JSONObject.parseObject(getUserInfoResult);
							String errcode = userOject.getString("errcode");
							String errmsg = userOject.getString("errmsg");
							if (errcode != null && !"".equals(errcode)) {
								log.info("查询微信用户信息失败！原因：" + errmsg);
							} else {
								String nickname = userOject.getString("nickname");
								int sex = userOject.getIntValue("sex");
								String city = userOject.getString("city");
								String country = userOject.getString("country");
								String province = userOject.getString("province");
								String headimgurl = userOject.getString("headimgurl");
								String subscribe = userOject.getString("subscribe");
								long subscribe_time = userOject.getLong("subscribe_time");
								String unionid = userOject.getString("unionid");
								String remark = userOject.getString("remark");
								String groupid = userOject.getString("groupid");
								String tagid_list = userOject.getString("tagid_list");

								wxUser.set("NickName", nickname);
								wxUser.set("Sex", sex);
								wxUser.set("City", city);
								wxUser.set("Country", country);
								wxUser.set("Province", province);
								wxUser.set("HeadImgUrl", headimgurl);
								wxUser.set("Subscribe", subscribe);
								wxUser.set("SubscribeTime", new Date(subscribe_time));
								wxUser.set("Unionid", unionid);
								wxUser.set("Remark", remark);
								wxUser.set("GroupId", groupid);
								wxUser.set("TagidList", tagid_list);
								wxUser.set("UpdatedBy", "System");
								wxUser.set("UpdatedDate", new Date());
								boolean isSuccess = wxUser.update();
								if (isSuccess) {
									log.info("更新OpenId为 [ " + openId + " ] 的用户信息成功！");
								} else {
									log.info("更新OpenId为 [ " + openId + " ] 的用户信息失败！");
								}
							}
						}
					} catch (Exception ex) {
						log.info("查询并保存微信用户信息异常！原因：" + ex.getMessage());
					}
				}
			}
		}catch (Exception e) {
			log.info("查询并保存微信用户信息异常！原因：" + e.getMessage());
		}
	}
	
	private static void updateBinding() {
		try {
			String token = getToken();
			List<WxUser> userList = WxUser.dao.getAllWxUser();
			if (userList != null && userList.size() > 0) {
				log.info("userList.size = " + userList.size());
				for (WxUser wxUser : userList) {

					String openId = wxUser.getStr("OpenId");
					log.info("openId = " + openId);

					// 获取绑定信息
					try {
						String getUserInfoUrl = "http://wechat.ami-tek.com.cn:50004/v1/users?serviceId=AMI&wxId=gh_e00c373bd430&openId="
								+ openId;
						String getUserInfoResult = HttpKit.get(getUserInfoUrl);
						log.info("getUserInfoResult = " + getUserInfoResult);
						if (getUserInfoResult != null && !"".equals(getUserInfoResult)) {
							JSONObject userOject = JSONObject.parseObject(getUserInfoResult);
							String status = userOject.getString("status");
							if ("OK".equalsIgnoreCase(status)) {
								JSONObject userTemp = userOject.getJSONObject("data");
								long deviceId = userTemp.getLong("deviceId");
								long bindOn = userTemp.getLong("bindOn");
								boolean alarmFlag = userTemp.getBoolean("alarmFlag");
								String nickName = userTemp.getString("nickName");
								String address = userTemp.getString("address");

								// 更新设备绑定信息
								DeviceBinding.dao.addDeviceBinding(deviceId, openId);

								wxUser.set("DeviceId", deviceId);
								wxUser.set("Address", address);
								wxUser.set("UpdatedBy", "System");
								wxUser.set("UpdatedDate", new Date());
								boolean isSuccess = wxUser.update();
								if (isSuccess) {
									log.info("更新OpenId为 [ " + openId + " ] 的用户绑定信息成功！");
								} else {
									log.info("更新OpenId为 [ " + openId + " ] 的用户绑定信息失败！");
								}
							} else {
								log.info("查询OpenId为 [ " + openId + " ] 的用户绑定信息失败！");
							}
						}
					} catch (Exception e) {
						log.info("查询用户绑定信息异常！原因：" + e.getMessage());
					}
				}
			}
		} catch (Exception e) {
			log.info("查询微信用户信息和用户绑定信息异常！原因：" + e.getMessage());
		}
	}

	private static boolean checkModel(long deviceId){
		boolean flag = true;
		Device info = Device.dao.getDevice(deviceId);
		if(info.getStr("Model").equals("SXYC001"))
			flag = false;
		return flag ;
	}
	/**
	 * 注册Service回调函数
	 */
	private static void registerCallback() {

		if (!RabbitService.isStarted()) {

			log.info("服务未启动，不能注册回调函数 ...");

		} else {

			serviceInstance = ServiceFactory.getServiceInstance();

			long[] deviceIds = null;

			// deviceIds = new long[] {
			// 186714602033499435L
			// };

			/*
			       目前主要用到以下几个回调函数： 
			   onConfigRequest 
			   onTrackStartNotify 
			   onAlarmNotify
			   onMediaUploadNotify 
			   onRequestNotify（暂时未使用）
			 */

			// 新终端设备激活回调函数
			NotifyDeviceCallback notifyDeviceCallback = new NotifyDeviceCallback() {
				@Override
				public void onDeviceActivate(long deviceId, DeviceInfo deviceInfo) {
					log.info("【新终端设备激活回调】");
					log.info("deviceId = " + deviceId);
					log.info("deviceInfo = " + deviceInfo.toString());

					// 保存设备信息
					Device.dao.saveDeviceInfo(deviceInfo);
				}
			};

			// 接入平台需要下发配置信息到终端设备回调函数
			RequestConfigCallback requestConfigCallback = new RequestConfigCallback() {
				@Override
				public void onConfigRequest(long deviceId) {
					log.info("【接入平台需要下发配置信息到终端设备回调】");
					log.info("deviceId = " + deviceId);

					BindStatus bindStatus = new BindStatus();
					DeviceInfo deviceInfo = getDeviceInfo(deviceId);
					log.info("onConfigRequest deviceInfo： " + deviceInfo.toString());

					// 保存设备信息
					Device.dao.saveDeviceInfo(deviceInfo);

//					bindStatus = getBindStatus(deviceId);
					
					// 解析设备信息获取serviceId
					String serviceId = getServiceId(deviceInfo);

					// 如果该设备归属于当前serviceId，则下发配置信息
					if (PropKit.get("serviceId", "").equalsIgnoreCase(serviceId)) {
						// 下发配置，如果失败则重试
						boolean isSuccess = false;
						String wxQrCodeUrl = "";
						String wxStatusUrl = "";
						String[] modelStrs = deviceInfo.model.split("-");
						String model = modelStrs[1];
						switch (model) {
						case "SXYC001":
							//获取二维码url 及 获取绑定状态url
							wxQrCodeUrl = PropKit.get("qrCode_url") + "?deviceId=" + deviceId;
							wxStatusUrl = PropKit.get("userBindStatus_url") + "?deviceId=" + deviceId;
							break;
						default:
							log.info("无用的 model : " + model);
							return;
						}
						log.info("model : " + model);
						log.info("wxQrCodeUrl = " + wxQrCodeUrl);
						log.info("wxStatusUrl = " + wxStatusUrl);
						while (!isSuccess) {
							try {
								Map<String, String> userConfig = null;
								serviceInstance.sendConfigStatus(deviceId, wxStatusUrl, wxQrCodeUrl, bindStatus,
										userConfig);
								isSuccess = true;
								log.info("设备 [ " + deviceId + " ] sendConfigStatus success ！");
							} catch (ServiceException sex) {
								log.error("sendConfigStatus exception：" + sex.getMessage());
							} catch (RemoteException rex) {
								log.error("sendConfigStatus exception：" + rex.getMessage());
							}
						}
					} else {
						log.info("设备 [ " + deviceId + " ] 不属于 serviceId [ " + serviceId + " ] ,忽略下发配置！");
					}
				}
			};

			// 终端设备上报报警信息回调函数
			NotifyAlarmCallback notifyAlarmCallback = new NotifyAlarmCallback() {
				@Override
				public void onAlarmReport(long deviceId, long trackId, Map<AlarmType, Integer> alarmData,
						PosInfo alarmPos, Long uploadId) {
					//检测model是否可用，暂时排除车佰度的CBD001型号
					if(checkModel(deviceId))	return;
					log.info("【终端设备上报报警信息回调】");
					log.info("deviceId = " + deviceId);
					log.info("trackId = " + trackId);
					log.info("alarmPos = " + alarmPos.toString());

					// DeviceInfo deviceInfo = getDeviceInfo(deviceId);
					// log.info("onAlarmReport deviceInfo： " +
					// deviceInfo.toString());

					String alarmType = "shark";
					boolean isSuccess = false;
					//如果发送失败重复发送（暂时取消，超时后无法获取到是否发送成功）
//					while (!isSuccess) {
//						isSuccess = sendAlarm(deviceId, trackId, alarmType);
//						try {
//							Thread.sleep(10000);
//						} catch (Exception e) {
//						}
//					}
					
					isSuccess = sendAlarm(deviceId, trackId, alarmType);
				}
			};

			// 终端设备的新行程启动回调函数
			NotifyTrackStartCallback notifyTrackStartCallback = new NotifyTrackStartCallback() {
				@Override
				public void onTrackStart(long deviceId, long trackId, boolean isPowerOn) {
					//检测model是否可用，暂时排除车佰度的CBD001型号
					if(checkModel(deviceId))	return;
					log.info("【终端设备的新行程启动回调】");
					log.info("deviceId = " + deviceId);
					log.info("trackId = " + trackId);
					log.info("isPowerOn = " + isPowerOn);

					// DeviceInfo deviceInfo = getDeviceInfo(deviceId);
					// log.info("onAlarmReport deviceInfo： " +
					// deviceInfo.toString());

					String alarmType = "start";
					boolean isSuccess = false;
					
					//如果发送失败重复发送（暂时取消，超时后无法获取到是否发送成功）
//					while (!isSuccess) {
//						isSuccess = sendAlarm(deviceId, trackId,alarmType);
//						try {
//							Thread.sleep(10000);
//						} catch (Exception e) {
//						}
//					}
					
					isSuccess = sendAlarm(deviceId, trackId,alarmType);
				}
			};

			// 终端设备的行程结束回调函数
			NotifyTrackStopCallback notifyTrackStopCallback = new NotifyTrackStopCallback() {
				@Override
				public void onTrackStop(long deviceId, long trackId, boolean isPowerOff, PosInfo posInfo,
						TrackInfo trackInfo, StatInfo statInfoArray) {
					//检测model是否可用，暂时排除车佰度的CBD001型号
					//if(checkModel(deviceId))	return;
					log.info("【终端设备的行程结束回调】");
					log.info("deviceId = " + deviceId);
					log.info("trackId = " + trackId);
					log.info("isPowerOff = " + isPowerOff);
					log.info("posInfo = " + posInfo);
					log.info("trackInfo = " + trackInfo.toString());
					log.info("statInfoArray = " + statInfoArray);
					
					String alarmType = "stop";
					saveDrivingrange(deviceId, trackInfo);
					sendAlarm(deviceId, trackId, alarmType);
				}
			};

			// 终端设备上传文件回调函数
			NotifyUploadCallback notifyUploadCallback = new NotifyUploadCallback() {
				@Override
				public void onMediaUpload(long deviceId, long sessionId, UploadType uploadType, String fileUrl,
						long fileSize) {
					log.info("【设备上传文件回调】");
					//检测model是否可用，暂时排除车佰度的CBD001型号
					if(checkModel(deviceId))	return;
					log.info("【设备上传文件回调】");
					log.info("deviceId = " + deviceId);
					log.info("sessionId = " + sessionId);
					log.info("uploadType = " + uploadType.toString());
					log.info("fileUrl = " + fileUrl);
					log.info("fileSize = " + fileSize);
					WxUser users = WxUser.dao.getWxUserByDeviceId(deviceId);
					MediaUpload media = new MediaUpload();
					String extension = fileUrl.substring(fileUrl.lastIndexOf(".")+1);
					String SaveAddress = SDKUtils.getAddress(deviceId);
					String type = "";
					if("bmp".equalsIgnoreCase(extension)||"png".equalsIgnoreCase(extension)||"jpg".equalsIgnoreCase(extension)||"gif".equalsIgnoreCase(extension)){
						type = "image";
					}else if("amr".equalsIgnoreCase(extension)||"mp3".equalsIgnoreCase(extension)){
						type = "voice";
					}else if("mp4".equalsIgnoreCase(extension)){
						type = "video";
					}
					media.set("OpenId", users.getStr("OpenId"));
					media.set("Address", SaveAddress);
					media.set("MediaType", type);
					media.set("DeviceId", deviceId);
					media.set("SessionId", sessionId);
					media.set("UploadType", uploadType.toString());
					media.set("FileUrl", fileUrl);
					media.set("FileSize", fileSize);
					boolean isSuccess = media.saveMediaUpload(media);
					if (isSuccess) {
						log.info("保存设备上传文件 [ " + media.toString() + " ] 成功！");
					} else {
						log.info("保存设备上传文件 [ " + media.toString() + " ] 失败！");
					}

					String coverPic = fileUrl;
					if (uploadType.getValue() == UploadType.UPLOAD_SHARE.getValue()) {
						if (fileUrl.contains(".mp4")) {
							coverPic = fileUrl.substring(0, fileUrl.lastIndexOf(".") + 1)+ "jpg";
						}
					} else if (uploadType.getValue() == UploadType.UPLOAD_TRACK.getValue()) {
						//行程结束
					}
					
					// 获取当前行程信息, 获取经纬度
					PosInfo posInfo = null;
					TrackInfo trackInfo = null;
					String address = "";
					Date lastTime = new Date();
					String stopPic = "";
					String lastTimeStr = "";
					TrackStatus trackStatus = SDKUtils.getLastTrackStatus(deviceId);
					if (trackStatus != null) {
						stopPic = trackStatus.stopPic;
						posInfo = trackStatus.posInfo;
						trackInfo = trackStatus.trackInfo;
						if(trackInfo!=null){
							lastTime = new Date(trackInfo.gatherTime);
						}else{
							log.info("未查询到设备 [ "+deviceId+" ] 的最后行程信息!");
						}
						if (posInfo != null) {
							double latitude = posInfo.latitude;
							double longitude = posInfo.longitude;
							// 调用百度或者腾讯地图获取位置信息
							address = QMapUtils.getAddress(latitude, longitude);
						}else{
							log.info("未查询到设备 [ "+deviceId+" ] 最后的位置信息!");
						}
						
						if (address == null || "".equals(address)) {
							address = "暂时无法获取地理位置信息";
						}
						lastTimeStr = sdf.format(lastTime);
					} else {
						log.info("未获取到设备["+deviceId+"]最后行程信息！");
					}
					
					String openId = "";
					WxUser user = WxUser.dao.getWxUserByDeviceId(deviceId);
					if(user!=null){
						openId = user.getStr("OpenId");
						if(openId!=null&&!"".equals(openId)){
							String uploadMedia_url = PropKit.get("uploadMedia_url")+"?fileUrl="+fileUrl+"&coverPic="+coverPic+"&openId="+openId+"&sessionId="+sessionId+"&uploadType="+uploadType.getValue();
							HttpKit.get(uploadMedia_url);
							//TODO 判断是否发送成功
						}else{
							log.info("设备["+deviceId+"]未绑定微信！");
						}
					}else{
						log.info("未找到设备["+deviceId+"]绑定的微信信息！");
					}

				}
			};

			// 终端设备上报OBD信息回调函数
			ReportObdCallback reportObdCallback = new ReportObdCallback() {
				@Override
				public void onObdReport(long deviceId, long trackId, List<ObdInfo> obdInfoArray) {
					//检测model是否可用，暂时排除车佰度的CBD001型号
					if(checkModel(deviceId))	return;
					log.info("【终端设备上报OBD信息回调】");
					log.info("deviceId = " + deviceId);
					log.info("trackId = " + trackId);
				}
			};

			// 终端设备上报位置信息回调函数
			ReportPosCallback reportPosCallback = new ReportPosCallback() {
				@Override
				public void onPosReport(long deviceId, long trackId, List<PosInfo> posInfoArray) {
					//检测model是否可用，暂时排除车佰度的CBD001型号
					if(checkModel(deviceId))	return;
					log.info("【终端设备上报位置信息回调】");
					log.info("deviceId = " + deviceId);
					log.info("trackId = " + trackId);

					// DeviceInfo deviceInfo = getDeviceInfo(deviceId);
					// Device.dao.saveDeviceInfo(deviceInfo);

				}
			};

			// 终端设备上报行程信息回调函数
			ReportTrackCallback reportTrackCallback = new ReportTrackCallback() {
				@Override
				public void onTrackReport(long deviceId, long trackId, List<TrackInfo> trackInfoArray) {
					//检测model是否可用，暂时排除车佰度的CBD001型号
					if(checkModel(deviceId))	return;
					log.info("【终端设备上报行程信息回调】");
					log.info("deviceId = " + deviceId);
					log.info("trackId = " + trackId);
				}
			};

			// 终端设备发送绑定/解绑请求回调函数
			RequestBindCallback requestBindCallback = new RequestBindCallback() {
				@Override
				public void onBindRequest(long deviceId, BindType bindType, String phone, String email, String qq,
						String weixin, String weibo, String other) {
					//检测model是否可用，暂时排除车佰度的CBD001型号
					if(checkModel(deviceId))	return;
					log.info("【终端设备发送绑定/解绑请求回调】");
					log.info("deviceId = " + deviceId);
					log.info("bindType = " + bindType.toString());
					log.info("phone = " + phone);
					log.info("email = " + email);
					log.info("qq = " + qq);
					log.info("weixin = " + weixin);
					log.info("weibo = " + weibo);
					log.info("other = " + other);
				}
			};

			// 终端设备发送计费查询请求回调函数
			RequestChargeCallback requestChargeCallback = new RequestChargeCallback() {
				@Override
				public void onChargeCheck(long deviceId, String iccid, String msisdn, String imsi) {
					//检测model是否可用，暂时排除车佰度的CBD001型号
					if(checkModel(deviceId))	return;
					log.info("【终端设备发送计费查询请求回调】");
					log.info("deviceId = " + deviceId);
					log.info("iccid = " + iccid);
					log.info("msisdn = " + msisdn);
					log.info("imsi = " + imsi);
				}
			};

			// 终端设备响应业务系统下发的请求, 返回请求结果回调函数
			ResponseResultCallback responseResultCallback = new ResponseResultCallback() {
				@Override
				public void onRequestResult(long deviceId, long requestId, int resultCode, String resultMsg,
						Map<String, String> resultData) {
					//检测model是否可用，暂时排除车佰度的CBD001型号
					if(checkModel(deviceId))	return;
					log.info("【终端设备响应业务系统下发的请求, 返回请求结果回调】");
					log.info("deviceId = " + deviceId);
					log.info("requestId = " + requestId);
					log.info("resultCode = " + resultCode);
					log.info("resultMsg = " + resultMsg);
				}
			};

			try {

				serviceInstance.registerCallback(notifyAlarmCallback, deviceIds);
				log.info("registerCallback 注册回调函数[NotifyAlarmCallback]执行完成！");

				serviceInstance.registerCallback(notifyDeviceCallback, deviceIds);
				log.info("registerCallback 注册回调函数[NotifyDeviceCallback]执行完成！");

				serviceInstance.registerCallback(notifyTrackStartCallback, deviceIds);
				log.info("registerCallback 注册回调函数[NotifyTrackStartCallback]执行完成！");

				serviceInstance.registerCallback(notifyTrackStopCallback, deviceIds);
				log.info("registerCallback 注册回调函数[NotifyTrackStopCallback]执行完成！");

				serviceInstance.registerCallback(notifyUploadCallback, deviceIds);
				log.info("registerCallback 注册回调函数[NotifyUploadCallback]执行完成！");

				serviceInstance.registerCallback(reportObdCallback, deviceIds);
				log.info("registerCallback 注册回调函数[ReportObdCallback]执行完成！");

				serviceInstance.registerCallback(reportPosCallback, deviceIds);
				log.info("registerCallback 注册回调函数[ReportPosCallback]执行完成！");

				serviceInstance.registerCallback(reportTrackCallback, deviceIds);
				log.info("registerCallback 注册回调函数[ReportTrackCallback]执行完成！");

				serviceInstance.registerCallback(requestBindCallback, deviceIds);
				log.info("registerCallback 注册回调函数[RequestBindCallback]执行完成！");

				serviceInstance.registerCallback(requestChargeCallback, deviceIds);
				log.info("registerCallback 注册回调函数[RequestChargeCallback]执行完成！");

				serviceInstance.registerCallback(requestConfigCallback, deviceIds);
				log.info("registerCallback 注册回调函数[RequestConfigCallback]执行完成！");

				serviceInstance.registerCallback(responseResultCallback, deviceIds);
				log.info("registerCallback 注册回调函数[ResponseResultCallback]执行完成！");

			} catch (ServiceException sex) {
				// 本地或网络错误，重试
				log.error("registerCallback Exception：本地或网络错误！");
			} catch (RemoteException rex) {
				// 参数或服务器错误，放弃
				log.error("registerCallback Exception：参数或服务器错误！");
			}
		}

	}

	/**
	 * 根据设备型号字符串获取ServiceId
	 * @param deviceModel 设备型号字符串
	 * @return
	 */
	public static String getServiceId(String deviceModel) {
		String serviceId = "";
		try {
			if (deviceModel != null) {
				String[] modelStrs = deviceModel.split("-");
				if (modelStrs.length > 0) {
					serviceId = modelStrs[0];
				}
			}
		} catch (Exception e) {
			log.error("根据设备信息获取serviceId异常，原因：" + e.getMessage());
		}
		return serviceId;
	}

	/**
	 * 根据设备信息获取ServiceId
	 * @param deviceInfo 设备信息
	 * @return
	 */
	public static String getServiceId(DeviceInfo deviceInfo) {
		if (deviceInfo != null) {
			return getServiceId(deviceInfo.model);
		}
		return "";
	}

	/**
	 * 根据设备Id获取设备信息
	 * @param deviceId 设备Id
	 * @return
	 */
	public static DeviceInfo getDeviceInfo(long deviceId) {
		DeviceInfo deviceInfo = null;
		try {
			deviceInfo = serviceInstance.queryDeviceInfo(deviceId);
		} catch (ServiceException sex) {
			log.error("getDeviceInfo exception：" + sex.getMessage());
		} catch (RemoteException rex) {
			log.error("getDeviceInfo exception：" + rex.getMessage());
		}
		log.info("deviceInfo： " + deviceInfo.toString());
		return deviceInfo;
	}

	public static void saveDrivingrange(long deviceId, TrackInfo trackInfo) {
		//用户日常启动信息
		Drivingrange driving = Drivingrange.dao.findFirst(
				"select id, Deviceid, Openid, 'Range', TodayRange, accelerateCnt, decelerateCnt from drivingrange where deviceid = "+deviceId);
		//用户行程信息
		if(trackInfo.totalMileage >= 0){
			log.info("003  trackInfo.totalMileage = "+trackInfo.totalMileage);
			DeviceBinding binding = DeviceBinding.dao.getWxUserByDeviceId(deviceId+"");
			log.info("004  binding : "+binding);
			String openId = "";
			if(binding != null)	openId = binding.getStr("OpenId");
			log.info("005  openId = "+openId);
			double todayRange = trackInfo.totalMileage/1000;//当天行驶里程        (单位:公里)
			long datetime = trackInfo.gatherTime - trackInfo.startTime;//当天行驶时间	(单位:毫秒)
			double time = datetime/(1000*3600);//	(单位:时)
			log.info("此行程里程数 ： " + todayRange + "   时间 ： " + time);
			if(driving != null){
				driving.set("Openid", openId)
					.set("Range", todayRange + driving.getDouble("Range"))
					.set("TodayDate", time + driving.getDouble("todaydate"))
					.set("TodayRange", todayRange + driving.getDouble("todayrange"))
					.set("AccelerateCnt", trackInfo.accelerateCnt + driving.getInt("accelerateCnt"))
					.set("DecelerateCnt", trackInfo.decelerateCnt + driving.getInt("decelerateCnt"))
					.update();
			}else{
				new Drivingrange().set("Deviceid", deviceId).set("Openid", openId)
								.set("Range", todayRange)
								.set("TodayRange", todayRange).set("TodayDate", time)
								.set("AccelerateCnt", trackInfo.accelerateCnt)
								.set("DecelerateCnt", trackInfo.decelerateCnt)
								.save();
			}
		}
	}
	
	/**
	 * 获取行程列表
	 */
	public static TrackList getTrackList(long deviceId, long starttime, long stoptime){
		TrackList trackList = null;
		try {
			trackList = serviceInstance.queryTrackInfo(deviceId, starttime, stoptime);
		} catch (Exception e) {
			log.error("queryTrackInfo exception……");
			return trackList;
		}
		return trackList;
	}
	
	/**
	 * 根据设备Id和行程Id获取行程信息
	 * @param deviceId 设备Id
	 * @param trackId 行程Id
	 * @return
	 */
	public static TrackStatus getTrackStatus(long deviceId, long trackId) {
		TrackStatus trackStatus = null;
		try {
			trackStatus = serviceInstance.queryTrackStatus(deviceId, trackId);
		} catch (ServiceException sex) {
			log.error("getTrackStatus exception：" + sex.getMessage());
		} catch (RemoteException rex) {
			log.error("getTrackStatus exception：" + rex.getMessage());
		}
		log.info("trackStatus： " + trackStatus.toString());
		return trackStatus;
	}
	
	/**
	 * 获取轨迹点
	 * @param deviceId
	 * @param trackId
	 * @param start
	 * @param end
	 * @return
	 */
	public static PosResult getPosInfos(long deviceId, long trackId, long start, long end) {
		PosResult posInfo = null;
		try {
			posInfo = serviceInstance.queryPosList(deviceId, trackId, start, end, 60);
		} catch (ServiceException sex) {
			log.error("getTrackStatus exception：" + sex.getMessage());
		} catch (RemoteException rex) {
			log.error("getTrackStatus exception：" + rex.getMessage());
		}
		return posInfo;
	}
	
	/**
	 * 根据设备Id和行程Id获取位置信息
	 * @param deviceId 设备Id
	 * @param trackId 行程Id
	 * @return
	 */
	public static PosInfo getPosInfo(long deviceId, long trackId){
		PosInfo posInfo = null;
		TrackStatus trackStatus = getTrackStatus(deviceId, trackId);
		if(trackStatus!=null){
			posInfo = trackStatus.posInfo;
		}
		return posInfo;
	}
	
	/**
	 * 根据设备Id和行程Id获取位置信息（等待）
	 * @param deviceId 设备Id
	 * @param trackId 行程Id
	 * @param waitSeconds 等待时间（秒）
	 * @return
	 */
	public static PosInfo getPosInfoWaiting(long deviceId, long trackId,int waitSeconds){
		PosInfo posInfo = null;
		boolean isSuccess = false;
		while(!isSuccess){
			TrackStatus trackStatus = getTrackStatus(deviceId, trackId);
			if(trackStatus!=null){
				posInfo = trackStatus.posInfo;
				if(posInfo!=null){
					isSuccess = true;
				}
			}else{
				//如果不存在行程信息则放弃获取位置
				isSuccess = true;
			}
			try {
				Thread.sleep(waitSeconds*1000);
			} catch (InterruptedException e) {
			}
		}
		return posInfo;
	}
	
	/**
	 * 根据设备Id获取最后行程信息
	 * @param deviceId 设备Id
	 * @return
	 */
	public static TrackStatus getLastTrackStatus(long deviceId) {
		TrackStatus trackStatus = null;
		try {
			trackStatus = serviceInstance.queryTrackStatus(deviceId, null);
			if (trackStatus != null && trackStatus.posInfo != null) {
				log.info("成功查询到设备["+deviceId+"]的上次行程信息！");
			} else {
				log.info("未查询到设备["+deviceId+"]上次行程信息，将从所有行程中获取最新 ...");
				// 重新查询
				LocalDateTime nowTime = LocalDateTime.now();
				TrackList trackList = serviceInstance.queryTrackInfo(deviceId,
						nowTime.getSecond() * 1000L - 7 * 24 * 60 * 60 * 1000, nowTime.getSecond() * 1000);
				if (trackList != null) {
					log.info("查询到设备["+deviceId+"]的历史行程："+trackList.size()+"条");
					ArrayList<TrackDesc> trackDescList = (ArrayList<TrackDesc>) trackList;
					Collections.sort(trackDescList, new Comparator<TrackDesc>() {
						@Override
						public int compare(TrackDesc o1, TrackDesc o2) {
							if (o1.trackStart > o2.trackStart) {
								return 1;
							} else if (o1.trackStart == o2.trackStart) {
								return 0;
							} else {
								return -1;
							}
						}
					});
					if(trackDescList!=null&&trackDescList.size()>0){
						TrackDesc tempTrack = trackDescList.get(0);
						if(tempTrack!=null){
							long trackId = tempTrack.trackId;
							trackStatus = getTrackStatus(deviceId, trackId);
						}
					}
				}else{
					log.info("未查询到设备["+deviceId+"]的历史行程！");
				}
			}
		} catch (ServiceException sex) {
			log.error("getLastTrackStatus exception：" + sex.getMessage());
		} catch (RemoteException rex) {
			log.error("getLastTrackStatus exception：" + rex.getMessage());
		}
		log.info("trackStatus： " + trackStatus.toString());
		return trackStatus;
	}
	
	/**
	 * 根据设备Id获取最后位置信息
	 * @param deviceId 设备Id
	 * @return
	 */
	public static PosInfo getLastPosInfo(long deviceId) {
		PosInfo posInfo = null;
		try {
			TrackStatus trackStatus = getLastTrackStatus(deviceId);
			if (trackStatus != null) {
				posInfo = trackStatus.posInfo;
			}
		} catch (Exception ex) {
			log.error("getLastPosInfo Exception：" + ex.getMessage());
		}
		return posInfo;
	}
	
	/**
	 * 下发设备绑定信息到指定终端
	 * @param deviceId 设备Id
	 * @param bindStatus 设备绑定状态
	 */
	public static void sendBindStatus(long deviceId, BindStatus bindStatus) {
		boolean isSuccess = false;
		//while (!isSuccess) {
			try {
				serviceInstance.sendBindStatus(deviceId, bindStatus);
				isSuccess = true;
				log.info(" deviceId [ "+deviceId+" ] sendBindStatus success! deviceId = " + deviceId);
			} catch (ServiceException sex) {
				log.error("deviceId [ "+deviceId+" ] sendBindStatus exception：" + sex.getMessage());
			} catch (RemoteException rex) {
				log.error("deviceId [ "+deviceId+" ] sendBindStatus exception：" + rex.getMessage());
			}
		//}
	}

	/**
	 * 下发设备绑定信息到指定终端
	 * @param deviceId 设备Id
	 */
	public static void sendBindStatus(long deviceId) {
		System.out.println("sendBindStatus");
		try {
			BindStatus bindStatus = getBindStatus(deviceId);
			sendBindStatus(deviceId, bindStatus);
		} catch (Exception e) {
			log.error("发送设备绑定状态异常！原因：" + e.getMessage());
		}
	}

	/**
	 * 根据设备Id获取设备绑定状态
	 * @param deviceId 设备Id
	 * @return
	 */
	public static BindStatus getBindStatus(long deviceId) {
		BindStatus bindStatus = new BindStatus();
		try {
			WxUser wxUser = WxUser.dao.getWxUserByDeviceId(deviceId);
			if (wxUser != null) {
				log.info("设备 [ " + deviceId + " ] 已经成功绑定微信 [ " + wxUser.getStr("OpenId") + " ] ！");
				// 如果已经绑定
				bindStatus.bindStatus = true;
				UserInfo userInfo = new UserInfo();
				String openId = wxUser.get("OpenId", "");
				userInfo.openId = openId;
				userInfo.nickName = wxUser.get("NickName", "");
				bindStatus.weixin = userInfo;
			} else {
				log.info("设备 [ " + deviceId + " ] 未绑定微信！");
			}
		} catch (Exception e) {
			log.error("查询设备绑定状态异常！原因：" + e.getMessage());
		}
		return bindStatus;
	}

	/**
	 * 根据设备Id和行程Id发送报警信息
	 * @param deviceId 设备Id
	 * @param trackId 行程Id
	 * @return
	 */
	public static boolean sendAlarm(long deviceId, long trackId) {
		return sendAlarm(deviceId, trackId, "");
	}

	/**
	 * 根据设备Id、行程Id和报警类型发送报警信息
	 * @param deviceId 设备Id
	 * @param trackId 行程Id
	 * @param alarmType 报警类型
	 * @return
	 */
	public static boolean sendAlarm(long deviceId, long trackId, String alarmType) {
		boolean isSuccess = false;
		try {
			DeviceInfo deviceInfo = getDeviceInfo(deviceId);
			// 解析设备信息获取serviceId
			String serviceId = getServiceId(deviceInfo);
			// 如果该设备归属于当前serviceId，则下发配置信息
			if (PropKit.get("serviceId", "").equalsIgnoreCase(serviceId)) {
				DeviceBinding binding = DeviceBinding.dao.findFirst(
						"select * from DeviceBinding where deviceId = ? and isAlarm = 1", new Object[] { deviceId });
				if (binding != null) {
					String iccid = "";
					String openId = binding.get("OpenId");
					String alarmUrl = PropKit.get("alarmNotify_url") + "?deviceId=" + deviceId + "&openId=" + openId
							+ "&iccid=" + iccid + "&trackId=" + trackId + "&alarmType=" + alarmType;
					log.info("alarmUrl = " + alarmUrl);
					String result = HttpKit.get(alarmUrl);
					String resultCode = "";
					String resultMessage = "";
					if (result != null && !"".equals(result)) {
						JSONObject jo = JSONObject.parseObject(result);
						if (jo != null) {
							resultCode = jo.getString("code");
							resultMessage = jo.getString("message");
						} else {
							log.info("设备 [ " + deviceId + " ] 给微信 [ " + openId + " ] 发送告警信息返回值为空！");
						}
					} else {
						log.info("设备 [ " + deviceId + " ] 给微信 [ " + openId + " ] 发送告警信息返回值为空！");
					}

					if ("0".equals(resultCode)) {
						isSuccess = true;
						log.info("设备 [ " + deviceId + " ] 给微信 [ " + openId + " ] 发送告警信息成功！");
					} else {
						log.info("设备 [ " + deviceId + " ] 给微信 [ " + openId + " ] 发送告警信息失败！原因：" + resultMessage);
					}
				} else {
					log.info("设备 [ " + deviceId + " ] 未查找到绑定的微信信息！");
				}
			} else {
				log.info("设备 [ " + deviceId + " ] 不属于 serviceId [ " + serviceId + " ] ,忽略发送告警信息！");
			}
		} catch (Exception e) {
			log.error("发送报警消息异常，原因：" + e.getMessage());
		}
		return isSuccess;
	}

	/**
	 * 根据位置信息获取地址
	 * @param posInfo 位置信息
	 * @return
	 */
	public static String getAddress(PosInfo posInfo){
		String address = "";
		try {
			if (posInfo != null&&posInfo.latitude!=null&&posInfo.longitude!=null) {
				double latitude = posInfo.latitude;
				double longitude = posInfo.longitude;
				// 调用百度或者腾讯地图获取位置信息
				address = QMapUtils.getAddress(latitude, longitude);
			}
		} catch (Exception e) {
			log.error("getAddress Exception："+e.getMessage());
		}
		if (address == null || "".equals(address)) {
			address = "暂时无法获取地理位置信息";
		}
		return address;
	}

	/**
	 * 根据行程状态获取地址
	 * @param trackStatus 行程状态
	 * @return
	 */
	public static String getAddress(TrackStatus trackStatus){
		String address = "暂时无法获取地理位置信息";
		if(trackStatus!=null){
			address = getAddress(trackStatus.posInfo);
		}
		return address;
	}

	/**
	 * 根据设备Id获取地址
	 * @param deviceId 设备Id
	 * @return
	 */
	public static String getAddress(long deviceId){
		String address = "暂时无法获取地理位置信息";
		TrackStatus trackStatus = SDKUtils.getLastTrackStatus(deviceId);
		if(trackStatus!=null){
			address = getAddress(trackStatus.posInfo);
		}
		return address;
	}

	/**
	 * 请求设备发送指定媒体文件
	 * @param deviceId 设备Id
	 * @param mediaType 媒体文件类型：0:图片 1:视频 2:音频
	 * @param uploadType 上传类型 ： 0:行程结束图片 1:分享 2:监控 3:报警 4:其他
	 * @param uploadCnt 请求上传的的文件参数. 对应图片，为上传图片数量；对应视频/音频，为上传视频/音频时间的秒数。
	 */
	public static boolean requestMedia(long deviceId, int mediaType, int uploadType, int uploadCnt){
		boolean isSuccess = false;
		try {
			long requestId = serviceInstance.requestMonitor(deviceId,MediaType.fromValue(mediaType),UploadType.fromValue(uploadType),uploadCnt,null,null);
			isSuccess = true;
		} catch (ServiceException sex) {
			log.error("requestMedia exception：" + sex.getMessage());
		} catch (RemoteException rex) {
			log.error("requestMedia exception：" + rex.getMessage());
		}
		return isSuccess;
	}
	
	/**
	 * 请求设备执行导航操作
	 * @param deviceId 设备Id
	 * @param groupName 群组名称，如果为null或者空, 则为非群组导航
	 * @param destArray 导航目标点数组
	 * @return
	 */
	public static boolean requestNavigate(long deviceId,String groupName,DestInfo destInfo){
		boolean isSuccess = false;
		try {
			DestInfo[] destArray = new DestInfo[]{destInfo};
			long requestId = serviceInstance.requestNavigate(deviceId,groupName,destArray,null);
			isSuccess = true;
		} catch (ServiceException sex) {
			log.error("requestNavigate exception：" + sex.getMessage());
		} catch (RemoteException rex) {
			log.error("requestNavigate exception：" + rex.getMessage());
		}
		return isSuccess;
	}
	
	/**
	 * 请求显示报警信息
	 * @param deviceId
	 * @param paramName 报警内容显示方式
	 * @param paramValue 报警内容
	 * @return
	 */
	public static boolean requestShowAlert(long deviceId,String[] paramName,String[] paramValue){
		boolean isSuccess = false;
		try {
			long requestId = serviceInstance.requestSystem(deviceId,ReqType.REQ_SHOW_ALERT,paramName,paramValue,null);
			isSuccess = true;
		} catch (ServiceException sex) {
			log.error("requestSystem exception：" + sex.getMessage());
		} catch (RemoteException rex) {
			log.error("requestSystem exception：" + rex.getMessage());
		}
		return isSuccess;
	}
	
}
